/******************************************************************************
 * Copyright (c) 2008-2010 Joel Becker. All Rights Reserved.
 * http://tech.joelbecker.net
 *
 *    This is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License
 *    version 3, as published by the Free Software Foundation.
 *
 *    This is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public
 *    License along with this source file; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 ******************************************************************************/
package tracking_algorithms.videoprocessing;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
import java.security.KeyStore.Builder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;

import javax.imageio.ImageIO;
import javax.media.format.VideoFormat;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import algos.ImageProcessingFilters;

/**
 * Applies a brightness threshold to each pixel in the RGB input. Input: 24-bit
 * color Output: 8-bit on/off (0/255)
 * 
 * @author Joel R. Becker
 * 
 */
public class RgbThresholdEffect extends RgbVideoEffect implements
		ChangeListener {

	private byte[] output;
	// private char threshold[] = new char[] {64, 64, 64};
	protected int threshold = 20;
	private JSlider thresholdSlider;
	public double alpha, beta, tH, tS;
	/** Number of pixels that passed the threshold. */
	protected int passCount;

	/** Ratio of pixels passing to pixels not passing. */
	public void setThresholdSlider(JSlider thrSlider) {
		thresholdSlider = thrSlider;
		if (thresholdSlider != null) {
			thresholdSlider.addChangeListener(this);
		}
	}

	public RgbThresholdEffect() {
	}

	public String getName() {
		return "RGB Threshold";
	}

	public void setBackGround(BackgroundUpdater ba) {
		bgUpdater = ba;
	}

	public void setThreshold(char threshold) {
		this.threshold = threshold;
	}

	public int getThreshold() {
		return threshold;
	}

	public byte[] getOut() {
		return output;
	}

	/**
	 * If either the R, G, or B components of a pixel pass the threshold, then
	 * the corresponding byte in the output buffer is set to 100% (255). NOTE:
	 * Output is a byte-per-pixel format, NOT 3 bytes per pixel.
	 */
	protected boolean processRGB(byte[] bin, byte[] bout, VideoFormat format) {
		long st = System.currentTimeMillis();
		if (backGroundImage != null) {
			passCount = 0;
			int p = 0;
			byte[] btest = new byte[bin.length];
			int w = format.getSize().width;
			int h = format.getSize().height;
			int k = 0;
			int j = 0;
			for (int i = 0; i < bin.length; i++, p++) {
				if ((char) bin[i] > threshold) {
					bout[p] = (byte) 255;
					btest[p] = (byte) 255;
					passCount++; // number of passed pixels

					if (testing)
						coloredInputImage.set(k, j, Color.white.getRGB());
				} else {
					bout[p] = 0;
					btest[p] = (byte) 0;
					if (testing)
						coloredInputImage.set(k, j, 0);
				}

				k++;
				if (k % w == 0) {
					k = 0;
					j = (j + 1) % h;

				}

			}

//			ImageProcessingFilters.medianFilter(backGroundArray);
//			ImageProcessingFilters.medianFilter(coloredBackGroundArray);

			passRatio = ((float) passCount / ((float) (format.getSize().width * format
					.getSize().height))) * 100.0f;
//			 try {
//			 ImageIO.write(coloredInputImage.getBufferedImage(), "png", new
//			 File("colored_"+num+".png"));
//			 
//			// // BufferedImage buim = new
//			// BufferedImage(backGroundArray[0].length, backGroundArray.length,
//			// BufferedImage.TYPE_BYTE_GRAY);
//			// // for (int i = 0; i < backGroundArray.length; i++) {
//			// // for (int l = 0; l < backGroundArray[0].length; l++) {
//			// // buim.setRGB(l, i, backGroundArray[i][l]);
//			// // }
//			// // }
//			// // ImageIO.write(buim, "png", new File("back_"+num+".png"));
//			 } catch (IOException e) {
//			 // TODO Auto-generated catch block
//			 e.printStackTrace();
//			 }
			output = bout;
		}
		long end = System.currentTimeMillis();
		// System.out.println(end-st);

		return true;
	}

	/**
	 * This function checks whether the given pixel is shadow or not. It works
	 * by getting the Hue, Saturation and brightness values of the pixels in the
	 * input image and the background image. The difference between the H, S and
	 * B is calculated between the two images. Some thresholds are applied to
	 * detect whether the pixel is shadow or not
	 */
	private boolean checkShadow(int i, int j, double alpha, double beta,
			double tH, double tS) {

		// split the color components
		int c = coloredInputImageArray[i][j];
		int red = (c & 0xff0000) >> 16;
		int green = (c & 0xff00) >> 8;
		int blue = c & 0xff;

		float hsb[] = new float[3];// get the hsb values.
		Color.RGBtoHSB(red, green, blue, hsb);

		float hI = hsb[0];
		float sI = hsb[1];
		float bI = hsb[2];

		c = coloredBackGroundArray[i][j];
		red = (c & 0xff0000) >> 16;
		green = (c & 0xff00) >> 8;
		blue = c & 0xff;

		Color.RGBtoHSB(red, green, blue, hsb);

		float hB = hsb[0];
		float sB = hsb[1];
		float bB = hsb[2];

		double r = bI / bB; // the ratio of the brightness
		double hDiff = Math.min(Math.abs(hI - hB), 360 - Math.abs(hI - hB));
		double sDiff = sI - sB;
		if (Double.compare(r, alpha) >= 0 && Double.compare(r, beta) <= 0
				&& Double.compare(hDiff, tH) <= 0
				&& Double.compare(sDiff, tS) <= 0)
			return true;
		return false;
	}

	/** Returns the number of pixels that passed in the last frame. */
	public int getPassCount() {
		return passCount;
	}

	/**
	 * Returns the ratio of pixels passing to pixels not passing, in the last
	 * frame.
	 */
	public float getPassRatio() {
		return passRatio;
	}

	@Override
	public void stateChanged(ChangeEvent e) {
		// TODO Auto-generated method stub
		if (e.getSource() == thresholdSlider) {
			threshold = ((JSlider) e.getSource()).getValue();
		}
	}
}
